package com.loit.business.utils;


import java.io.*;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.*;

/**
 * 平台代码生成工具
 *
 * @author lifh
 * @version v1.0
 * @date 2022-12-15
 */
class GeneratorUtils {


    ///////////////////////////TODO 代码生成  内部为使用者所需修改的内容//////////////////////////////////////////////////////////
    /**
     * 必要配置-项目中文名称
     */
    protected String projectName = "测试测试脚手架";
    
    /**
     * 必要配置-生成的文件存放目录
     */
    protected String root_path = "D:\\MyWork\\IdeaWorkSpace\\loit-scaffolding\\loit-business";
    
    /**
     * 作者名称
     */
    protected String author = "lifh";
    /**
     * 请求头
     */
    protected String request = "/api/v1/";
    /**
     * 要生成代码的数据库表名, 如果为空则生成该数据库内全部的表对应的代码文件
     */
    protected String customTableNames[] = {
            "test_student"
    };

    /**
     * 包路径配置
     */
    private final String bean_package = "com.loit.business.entity";
    private final String service_package = "com.loit.business.service";
    private final String dao_package = "com.loit.business.dao";
    private final String controller_package = "com.loit.business.controller";
    private final String dto_package = "com.loit.business.dto";


    /**
     * 生成的带代码文件名称忽略表名前缀, 可选项：不忽略则"
     */
    protected String excludTablePrefix = "test_";

    /**
     * 必要配置-数据库相关配置
     */
    protected String url = "jdbc:mysql://43.143.182.32:3306/mytest1?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8";
    protected String driverName = "com.mysql.cj.jdbc.Driver";
    protected String user = "root";
    protected String password = "123456";

    /////////////////////////////////////////////////////////////////////////////////////
    /**
     * 执行
     */
    public static void main(String[] args) {
        try {
            GeneratorUtils generator = new GeneratorUtils();
            generator.generate();
            // 自动打开生成文件的目录
            Runtime.getRuntime().exec("cmd /c start explorer " + generator.root_path_full.replace("/", "\\"));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.exit(0);
    }
    
    /**
     * 生成代码主入口方法
     */
    public void generate() throws ClassNotFoundException, SQLException, IOException {
        init();
        String prefix = "show full fields from ";
        List<String> columns = null;
        List<String> types = null;
        List<String> comments = null;
        PreparedStatement pstate = null;
        List<String> tables = getTables();
        Map<String, String> tableComments = getTableComment();
        for (String table : tables) {
            if ("schema_version".equalsIgnoreCase(table))
                continue;
            columns = new ArrayList<String>();
            types = new ArrayList<String>();
            comments = new ArrayList<String>();
            tableName = table;
            tableNameFull = this.excludTablePrefix + table;
            pstate = conn.prepareStatement(prefix + tableNameFull);
            ResultSet results = pstate.executeQuery();
            while (results.next()) {
                columns.add(results.getString("FIELD").toLowerCase());
                types.add(results.getString("TYPE").toLowerCase());
                comments.add(results.getString("COMMENT").toLowerCase());
            }
            processTable(tableName);
            String tableComment = tableComments.get(tableNameFull);
            createRootDir(this.root_path_full);
            
            buildEntityBean(columns, types, comments, tableComment, this.beanName, this.bean_package, this.bean_path);
            buildDao(tableComment);
            buildMapperXml(columns, types, comments, tableComment);
            buildService(this.service_path, this.serviceName, this.service_package, tableComment, types);
            buildController(this.controller_path, this.controllerName, this.controller_package, columns, types, comments, tableComment);
        }
        conn.close();
    }

    /**
     * 其他路径配置
     */
    protected String root_path_full = root_path + "/src/main/java/com/loit/business";
    protected String bean_path = root_path + "/src/main/java/com/loit/business/entity";
    protected String mapper_path = root_path + "/src/main/java/com/loit/business/dao";
    protected String xml_path = root_path + "/src/main/resources/mapper";
    protected String service_path = root_path + "/src/main/java/com/loit/business/service";
    protected String controller_path = root_path + "/src/main/java/com/loit/business/controller";


    private String tableName = null;
    private String tableNameFull = null;
    private String beanName = null;
    private String mapperName = null;
    private String daoName = null;
    private String dtoName = null;
    private String serviceName = null;
    private String controllerName = null;

    /**
     * myssql数据库的数据类型，代码中判断使用
     */
    private final String type_char = "char";
    private final String type_date = "date";
    private final String type_timestamp = "timestamp";
    private final String type_int = "int";
    private final String type_bigint = "bigint";
    private final String type_text = "text";
    private final String type_bit = "bit";
    private final String type_decimal = "decimal";
    private final String type_blob = "blob";
    private final String type_float = "float";
    private final String type_double = "double";

    private Connection conn = null;
    private void init() throws ClassNotFoundException, SQLException {
        Class.forName(driverName);
        conn = DriverManager.getConnection(url, user, password);
    }
    
    /**
     * 获取所有的表名
     *
     * @return
     * @throws SQLException
     */
    private List<String> getTables() throws SQLException {
        List<String> tables = new ArrayList<String>();
        PreparedStatement pstate = conn.prepareStatement("show tables");
        ResultSet results = pstate.executeQuery();
        while (results.next()) {
            // 是否输出自定义的表
            if (this.customTableNames.length > 0) {
                for (String customTableName : customTableNames) {
                    String tableName = results.getString(1);
                    if (customTableName.toUpperCase().equalsIgnoreCase(tableName)) {
                        if (tableName.toLowerCase().startsWith(excludTablePrefix.toLowerCase())) {
                            customTableName = customTableName.substring(excludTablePrefix.length());
                        }
                        tables.add(customTableName);
                    }
                }
            } else {
                String tableName = results.getString(1);
                tables.add(tableName);
            }
        }

        return tables;
    }

    /**
     * 根据表明拼接各个文件名称
     * @param table
     */
    private void processTable(String table) {
        StringBuffer sb = new StringBuffer(table.length());
        String tableNew = table.toLowerCase();
        String[] tables = tableNew.split("_");
        String temp = null;
        for (int i = 0; i < tables.length; i++) {
            temp = tables[i].trim();
            sb.append(temp.substring(0, 1).toUpperCase()).append(temp.substring(1));
        }
        beanName = sb.toString() + "";
        mapperName = sb.toString() + "DaoMapper";
        daoName = sb.toString() + "Dao";
        dtoName = sb.toString() + "DTO";
        serviceName = sb.toString() + "Service";
        controllerName = sb.toString() + "Controller";
    }

    private String processType(String type) {
        if (type.indexOf(type_char) > -1) {
            return "String";
        } else if (type.indexOf(type_bigint) > -1) {
            return "Long";
        } else if (type.indexOf(type_int) > -1) {
            return "Integer";
        } else if (type.indexOf(type_date) > -1) {
            return "Date";
        } else if (type.indexOf(type_text) > -1) {
            return "String";
        } else if (type.indexOf(type_timestamp) > -1) {
            return "Date";
        } else if (type.indexOf(type_bit) > -1) {
            return "Boolean";
        } else if (type.indexOf(type_decimal) > -1) {
            return "java.lang.Float";
        } else if (type.indexOf(type_blob) > -1) {
            return "byte[]";
        } else if (type.indexOf(type_float) > -1) {
            return "Float";
        }else if (type.indexOf(type_double) > -1) {
            return "Double";
        }
        return null;
    }


    private String processTypeDTO(String type) {
        if (type.indexOf(type_char) > -1) {
            return "String";
        } else if (type.indexOf(type_bigint) > -1) {
            return "Long";
        } else if (type.indexOf(type_int) > -1) {
            return "Integer";
        } else if (type.indexOf(type_date) > -1) {
            return "Long";
        } else if (type.indexOf(type_text) > -1) {
            return "String";
        } else if (type.indexOf(type_timestamp) > -1) {
            return "Long";
        } else if (type.indexOf(type_bit) > -1) {
            return "Boolean";
        } else if (type.indexOf(type_decimal) > -1) {
            return "java.lang.Float";
        } else if (type.indexOf(type_blob) > -1) {
            return "byte[]";
        }
        return null;
    }

    private String processField(String field) {
        StringBuffer sb = new StringBuffer(field.length());
        String[] fields = field.split("_");
        String temp = null;
        sb.append(fields[0]);
        for (int i = 1; i < fields.length; i++) {
            temp = fields[i].trim();
            sb.append(temp.substring(0, 1).toUpperCase()).append(temp.substring(1));
        }
        return sb.toString();
    }

    /**
     * 将实体类名首字母改为小写
     *
     * @param beanName
     * @return
     */
    @SuppressWarnings("unused")
    private String processResultMapId(String beanName) {
        return beanName.substring(0, 1).toLowerCase() + beanName.substring(1);
    }

    private String processResultMapIdUpper(String beanName) {

        if (beanName.contains("_")) {
            String name = "";
            String strs[] = beanName.split("_");
            for (String str : strs) {
                name += str.substring(0, 1).toUpperCase() + str.substring(1);
            }
            return name;
        }

        return beanName.substring(0, 1).toUpperCase() + beanName.substring(1);
    }

    /**
     * 构建类上面的注释
     *
     * @param bw
     * @param text
     * @return
     * @throws IOException
     */
    private BufferedWriter buildClassComment(BufferedWriter bw, String text) throws IOException {
        bw.newLine();
        bw.newLine();
        bw.write("/**");
        bw.newLine();
        bw.write(" * " + text);
        bw.newLine();
        bw.write(" * Created" + (this.stringNotNull(this.author) ? " by " + this.author + "" : "") + " on " + this.getDate() + ".");
        bw.newLine();
        bw.write(" **/");
        return bw;
    }

    /**
     * 构建方法上面的注释
     *
     * @param bw
     * @param text
     * @return
     * @throws IOException
     */
    private BufferedWriter buildMethodComment(BufferedWriter bw, String text) throws IOException {
        bw.newLine();
        bw.write("\t/**");
        bw.newLine();
        bw.write("\t * ");
        bw.newLine();
        bw.write("\t * " + text);
        bw.newLine();
        bw.write("\t * ");
        bw.newLine();
        bw.write("\t **/");
        return bw;
    }

    /**
     * 创建根目录
     */
    private void createRootDir(String rootPath) {
        File folder = new File(rootPath);
        if (!folder.exists()) {
            folder.mkdir();
        }
    }
    
    

    /**
     * 生成实体类
     *
     * @param columns
     * @param types
     * @param comments
     * @throws IOException
     */
    private void buildEntityBean(List<String> columns, List<String> types, List<String> comments, String tableComment,
                                 String className, String packName, String path) throws IOException {
        File folder = new File(path);
        if (!folder.exists()) {
            folder.mkdir();
        }

        File beanFile = new File(path, className + ".java");
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(beanFile)));
        bw.write("package " + packName + ";");
        bw.newLine();
        bw.newLine();
//        bw.write("import com.loit.common.persistence.dao.DataEntity;");
//        bw.newLine();
        bw.write("import com.baomidou.mybatisplus.annotation.IdType;");
        bw.newLine();
        bw.write("import com.baomidou.mybatisplus.annotation.TableId;");
        bw.newLine();
        bw.write("import com.loit.loitcommon.utils.ExcelField;");
        bw.newLine();
//        bw.write("import com.fasterxml.jackson.annotation.JsonFormat;");
//        bw.newLine();
        bw.write("import com.baomidou.mybatisplus.annotation.TableName;");
        bw.newLine();
        bw.write("import io.swagger.annotations.ApiModel;");
        bw.newLine();
        bw.write("import io.swagger.annotations.ApiModelProperty;");
        bw.newLine();
        bw.write("import lombok.AllArgsConstructor;");
        bw.newLine();
//        bw.write("import lombok.Builder;");
//        bw.newLine();
        bw.write("import lombok.Data;");
        bw.newLine();
        bw.write("import lombok.NoArgsConstructor;");
        bw.newLine();
        bw.write("import java.io.Serializable;");
        bw.newLine();
        bw.write("import java.util.Date;");
        bw.newLine();
        bw = buildClassComment(bw, (this.stringNotNull(tableComment) ? tableComment + " " : "") + "[" + this.projectName + "]数据对象.");
        bw.newLine();
        bw.write("@Data");
        bw.newLine();
//        bw.write("@Builder");
//        bw.newLine();
        bw.write("@AllArgsConstructor");
        bw.newLine();
        bw.write("@NoArgsConstructor");
        bw.newLine();
        bw.write("@ApiModel(value = \""+className+"\", description = \"" + (this.stringNotNull(tableComment) ? tableComment : className) + "对象\")");
        bw.newLine();
        bw.write("@TableName(value = \""+tableNameFull+"\")");
        bw.newLine();
        bw.write("public class " + className + " implements Serializable {");
        bw.newLine();
        bw.newLine();
        int size = columns.size();
        for (int i = 0; i < size; i++) {
            if (!columns.get(i).equalsIgnoreCase("DEL_FLAG") && !columns.get(i).equalsIgnoreCase("UPDATE_TIME")
                    && !columns.get(i).equalsIgnoreCase("CREATE_TIME")
            ){
                if (this.stringNotNull(comments.get(i))) {
                    bw.write("\t/**");
                    bw.newLine();
                    bw.write("\t * " + comments.get(i));
                    bw.newLine();
                    bw.write("\t */");
                    bw.newLine();
                    bw.write("	@ApiModelProperty(value = \"" + comments.get(i) + "\")");
                    bw.newLine();
                    bw.write("	@ExcelField(title = \"" + comments.get(i) + "\",align = 2, sort = " + (i+1) + ")");
                } else {
                    bw.write("	@ApiModelProperty(value = \"" + columns.get(i) + "\")");
                    bw.newLine();
                    bw.write("	@ExcelField(title = \"\",align = 2, sort = " + (i+1) + ")");
                }
                //设置实体类对应主键id，默认id为第一个字段才可生效，可在此修改id生成测率，但需注意表中该主键的类型和长度是否于生成策略匹配
                if (i == 0){
                    bw.newLine();
                    bw.write("\t@TableId(value = \"id\", type = IdType.AUTO)    //采用主键自增策略，同时数据库也是主键自增才可以生效");
                }
                bw.newLine();
                if(processType(types.get(i)).equals("Date")){
                    bw.write("	@JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")");
                    bw.newLine();
                }
                bw.write("\tprivate " + processType(types.get(i)) + " " + processField(columns.get(i)) + ";");
                bw.newLine();
                bw.newLine();
            }
        }
        // 生成get 和 set方法
//        String tempField = null;
//        String _tempField = null;
//        String tempType = null;
//        for (int i = 0; i < size; i++) {
//            if (!columns.get(i).equalsIgnoreCase("DEL_FLAG")
//                    && !columns.get(i).equalsIgnoreCase("UPDATE_TIME")
//            ){
//                tempType = processType(types.get(i));
//                _tempField = processField(columns.get(i));
//                tempField = _tempField.substring(0, 1).toUpperCase() + _tempField.substring(1);
//                bw.newLine();
//                bw.write("\tpublic void set" + tempField + "(" + tempType + " " + _tempField + "){");
//                bw.newLine();
//                bw.write("\t\tthis." + _tempField + " = " + _tempField + ";");
//                bw.newLine();
//                bw.write("\t}");
//                bw.newLine();
//                bw.newLine();
//                bw.write("\tpublic " + tempType + " get" + tempField + "(){");
//                bw.newLine();
//                bw.write("\t\treturn this." + _tempField + ";");
//                bw.newLine();
//                bw.write("\t}");
//                bw.newLine();
//            }
//        }
        bw.newLine();
        bw.write("}");
        bw.newLine();
        bw.flush();
        bw.close();
    }

    /**
     * 生成DTO
     *
     * @param columns
     * @param types
     * @param comments
     * @throws IOException
     */
    private void buildDto(List<String> columns, List<String> types, List<String> comments, String tableComment,
                          String className, String packName, String path) throws IOException {
        File folder = new File(path);
        if (!folder.exists()) {
            folder.mkdir();
        }

        File beanFile = new File(path, className + ".java");
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(beanFile)));
        bw.write("package " + packName + ";");
        bw.newLine();
        bw.newLine();
        bw.write("import io.swagger.annotations.ApiModel;");
        bw.newLine();
        bw.write("import io.swagger.annotations.ApiModelProperty;");
        bw.newLine();
        bw.write("import com.gocom.imoss.common.DTO.BaseDTO;");
        bw.newLine();
        bw = buildClassComment(bw, (this.stringNotNull(tableComment) ? tableComment + " " : "") + "[" + this.projectName + "]DTO.");
        bw.newLine();
        bw.write("@ApiModel(value = \"" + (this.stringNotNull(tableComment) ? tableComment : className) + "对象\")");
        bw.newLine();
        bw.write("public class " + className + " extends BaseDTO {");
        bw.newLine();
        bw.newLine();
        int size = columns.size();
        for (int i = 0; i < size; i++) {
            if (this.stringNotNull(comments.get(i))) {
                bw.write("\t/**");
                bw.newLine();
                bw.write("\t * " + comments.get(i));
                bw.newLine();
                bw.write("\t */");
                bw.newLine();
                bw.write("	@ApiModelProperty(value = \"" + comments.get(i) + "\")");
            } else {
                bw.write("	@ApiModelProperty(value = \"" + columns.get(i) + "\")");
            }
            bw.newLine();

            if (columns.get(i).equalsIgnoreCase("id")) {
                bw.write("\tpublic  Long " + processResultMapIdUpper(columns.get(i)) + ";");
            } else {
                bw.write("\tpublic " + processTypeDTO(types.get(i)) + " " + processResultMapIdUpper(columns.get(i)) + ";");
            }
            bw.newLine();
            bw.newLine();
        }
        bw.newLine();
        bw.write("}");
        bw.newLine();
        bw.flush();
        bw.close();
    }


    /**
     * 生成Dao文件
     *
     * @throws IOException
     */
    private void  buildDao(String tableComment) throws IOException {
        File folder = new File(mapper_path);
        if (!folder.exists()) {
            folder.mkdirs();
        }

        File mapperFile = new File(mapper_path, this.daoName + ".java");
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(mapperFile), "utf-8"));
        bw.write("package " + dao_package + ";");
        bw.newLine();
        bw.newLine();
        bw.write("import com.baomidou.mybatisplus.core.mapper.BaseMapper;");
        bw.newLine();
        bw.write("import com.baomidou.mybatisplus.core.metadata.IPage;");
        bw.newLine();
        bw.write("import com.baomidou.mybatisplus.extension.plugins.pagination.Page;");
        bw.newLine();
        bw.write("import " + this.bean_package + "." + this.beanName + ";");
        bw.newLine();
        bw.write("import org.apache.ibatis.annotations.Mapper;");
        bw.newLine();
        bw.write("import org.apache.ibatis.annotations.Param;");
        bw.newLine();
        bw.write("import org.springframework.stereotype.Repository;");
        bw.newLine();
        bw.write("import java.util.List;");
        bw.newLine();
        bw = buildClassComment(bw, "[" + (this.stringNotNull(tableComment) ? tableComment + " " : "") + "]数据层数据库操作接口类.");
        bw.newLine();
        bw.write("@Mapper");
        bw.newLine();
        bw.write("@Repository");
        bw.newLine();
        bw.write("public interface " + daoName + " extends BaseMapper<" + this.beanName + "> {");
        bw.newLine();
        bw.newLine();
        bw.write("    IPage<"+this.beanName+"> findList(Page<"+this.beanName+"> page, @Param(\""+processResultMapId(this.beanName)+"\") "+this.beanName+" "+processResultMapId(this.beanName)+");");
        bw.newLine();
        bw.newLine();
        bw.write("    List<"+this.beanName+"> findList(@Param(\""+processResultMapId(this.beanName)+"\") "+this.beanName+" "+processResultMapId(this.beanName)+");");
        bw.newLine();
        bw.write("\t");
        bw.newLine();
        bw.write("}");
        bw.flush();
        bw.close();
    }

    /**
     * 构建实体类映射XML文件
     *
     * @param columns
     * @param types
     * @param comments
     * @throws IOException
     */
    private void buildMapperXml(List<String> columns, List<String> types, List<String> comments, String tableComment)
            throws IOException {
        File folder = new File(xml_path);
        if (!folder.exists()) {
            folder.mkdirs();
        }

        File mapperXmlFile = new File(xml_path, mapperName + ".xml");
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(mapperXmlFile)));
        bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        bw.newLine();
        bw.write("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" ");
        bw.newLine();
        bw.write("    \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">");
        bw.newLine();
        bw.newLine();
        bw.write("<!-- " + this.tableNameFull + " " + tableComment + " -->");
        bw.newLine();
        bw.write("<mapper namespace=\"" + dao_package + "." + this.daoName + "\">");
        bw.newLine();
        bw.newLine();
        buildSQL(bw, columns, types);
        bw.write("</mapper>");
        bw.flush();
        bw.close();
    }

    private void buildSQL(BufferedWriter bw, List<String> columns, List<String> types) throws IOException {
        String resultMapName = "entityResultMap";
        String beanNameFull = this.bean_package + "." + this.beanName;
        int size = columns.size();
        bw.write("\t<resultMap id=\"" + resultMapName + "\" type=\"" + beanNameFull + "\">");
        bw.newLine();
        for (String column : columns) {
            String tempField = processField(column);
            if ("id".equalsIgnoreCase(column)) {
                bw.write("\t\t<id property=\"" + tempField + "\" column=\"" + column + "\" />");
            } else {
                bw.write("\t\t<result property=\"" + tempField + "\" column=\"" + column + "\"/>");
            }
            bw.newLine();
        }
        bw.write("\t</resultMap>");
        bw.newLine();
        bw.newLine();
        bw.write("\t<sql id=\"base\">");
        bw.newLine();
        for (int i = 0; i < size; i++) {
            bw.write("\t\t`" + columns.get(i) + "`");
            if (i != size - 1) {
                bw.write(",");
            }
            bw.newLine();
        }
        bw.write("\t</sql>");
        bw.newLine();
        bw.newLine();
        bw.write("\t<!-- 查询 -->");
        bw.newLine();
        bw.write("\t<select id=\"get\" resultMap=\"" + resultMapName + "\">");
        bw.newLine();
        bw.write("\t\t SELECT ");
        bw.newLine();
        bw.write("\t\t\t<include refid=\"base\"></include>");
        bw.newLine();
//        for (int i = 0; i < size; i++) {
//            bw.write("\t\t\t`" + columns.get(i) + "`");
//            if (i != size - 1) {
//                bw.write(",");
//            }
//            bw.newLine();
//        }
        bw.write("\t\t FROM " + tableNameFull);
        bw.newLine();
        bw.write("\t\t WHERE " + columns.get(0) + " = #{"+processField(columns.get(0))+"}");
        bw.newLine();
        bw.write("\t</select>");
        bw.newLine();
        bw.newLine();

        bw.write("\t<!-- 查询列表 -->");
        bw.newLine();
        bw.write("\t<select id=\"findList\" resultMap=\"" + resultMapName + "\" parameterType=\"" + beanNameFull + "\">");
        bw.newLine();
        bw.write("\t\tSELECT");
        bw.newLine();
        bw.write("\t\t\t<include refid=\"base\"></include>");
        bw.newLine();
//        for (int i = 0; i < size; i++) {
//            bw.write("\t\t\t`" + columns.get(i) + "`");
//            if (i != size - 1) {
//                bw.write(",");
//            }
//            bw.newLine();
//        }
        bw.write("\t\tFROM " + tableNameFull);
        bw.newLine();
        bw.write("\t\tWHERE 1=1 ");
        bw.newLine();
        
        for (int i=0;i<columns.size();i++) {
        	String column = columns.get(i);
            String tempField = processField(column);
            String type = processType(types.get(i));
            
	        bw.write("\t\t<if test=\""+processResultMapId(this.beanName)+"."+tempField+"!=null "+ (type.equals("String") ? "and " +processResultMapId(this.beanName)+"."+ tempField + "!=''" : "") +"\">");
	        bw.newLine();
	        bw.write("\t\t\tAND "+column+" = #{"+processResultMapId(this.beanName)+"."+tempField+"}");
	        bw.newLine();
	        bw.write("\t\t</if>");
	        bw.newLine();
        }
        
        bw.write("\t\t");
        bw.newLine();
        
        bw.write("\t</select>");
        bw.newLine();
        bw.newLine();

        bw.write("\t<!-- 保存 -->");
        bw.newLine();
        bw.write("\t<insert id=\"insert\" parameterType=\"" + beanNameFull + "\">");
        bw.newLine();
        bw.write("\t\t INSERT INTO " + tableNameFull);
        bw.newLine();
        bw.write(" \t\t\t(");
        for (int i = 1; i < size; i++) {
            bw.write(columns.get(i));
            if (i != size - 1) {
                bw.write(",");
            }
        }
        bw.write(") ");
        bw.newLine();
        bw.write("\t\t VALUES ");
        bw.newLine();
        bw.write(" \t\t\t(");
        for (int i = 1; i < size; i++) {
            bw.write("#{" + processField(columns.get(i)) + "}");
            if (i != size - 1) {
                bw.write(",");
            }
        }
        bw.write(") ");
        bw.newLine();
        bw.write("\t</insert>");
        bw.newLine();
        bw.newLine();


//        bw.write("\t<!-- 更新 -->");
//        bw.newLine();
//        bw.write("\t<update id=\"update\" parameterType=\"" + beanNameFull + "\">");
//        bw.newLine();
//        bw.write("\t\tUPDATE " + tableNameFull);
//        bw.newLine();
//        bw.write("\t\t<trim prefix=\"SET\" suffixOverrides=\",\" > ");
//        bw.newLine();
//        String tempField = null;
//        for (int i = 1; i < size; i++) {
//            tempField = processField(columns.get(i));
//            String type = processType(types.get(i));
//
//	        bw.write("\t\t\t<if test=\""+tempField+"!=null "+ (type.equals("String") ? "and " + tempField + "!=''" : "") +"\">");
//	        bw.newLine();
//            bw.write("\t\t\t\t" + columns.get(i) + " = #{" + tempField + "}");
//            if (i != size - 1) {
//                bw.write(",");
//            }
//            bw.newLine();
//            bw.write("\t\t\t</if>");
//	        bw.newLine();
//        }
//        bw.write("\t\t</trim>");
//        bw.newLine();
//        bw.write("\t\tWHERE " + columns.get(0) + " = #{" + processField(columns.get(0)) + "}");
//        bw.newLine();
//        bw.write("\t</update>");
//        bw.newLine();
//        bw.newLine();
//
//        bw.write("\t<!-- 删除 -->");
//        bw.newLine();
//        bw.write("\t<delete id=\"delete\">");
//        bw.newLine();
//        bw.write("\t\tdelete from " + tableNameFull + " where " + columns.get(0) + " = #{" + processField(columns.get(0)) + "}");
//        bw.newLine();
//        bw.write("\t</delete>");
//        bw.newLine();
//        bw.newLine();

    }

    /**
     * 获取所有的数据库表注释
     *
     * @return
     * @throws SQLException
     */
    private Map<String, String> getTableComment() throws SQLException {
        Map<String, String> maps = new HashMap<String, String>();
        PreparedStatement pstate = conn.prepareStatement("show table status");
        ResultSet results = pstate.executeQuery();
        while (results.next()) {
            String tableName = results.getString("NAME");
            String comment = results.getString("COMMENT");
            maps.put(tableName, comment);
        }
        return maps;
    }

    /**
     * 生成Service
     */
    private void buildService(String path, String className, String packName, String tableComment, List<String> types) throws IOException {

        File folder = new File(path);
        if (!folder.exists()) {
            folder.mkdir();
        }

        File beanFile = new File(path, className + ".java");
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(beanFile)));
        String minMapperName = daoName;
        minMapperName = minMapperName.substring(0, 1).toLowerCase() + minMapperName.substring(1);

        bw.write("package " + packName + ";");
        bw.newLine();
        bw.newLine();
        bw.write("import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;");
        bw.newLine();
        bw.write("import com.baomidou.mybatisplus.core.metadata.IPage;");
        bw.newLine();
        bw.write("import com.baomidou.mybatisplus.extension.plugins.pagination.Page;");
        bw.newLine();
        bw.write("import org.springframework.beans.factory.annotation.Autowired;");
        bw.newLine();
        bw.write("import org.springframework.stereotype.Service;");
        bw.newLine();
        bw.write("import org.springframework.transaction.annotation.Transactional;");
        bw.newLine();
        bw.write("import " + this.dao_package + "." + this.daoName + ";");
        bw.newLine();
        bw.write("import " + this.bean_package + "." + this.beanName + ";");
        bw.newLine();
        bw.write("import java.util.List;");
        bw.newLine();
        bw.newLine();
        bw = buildClassComment(bw,  "[" + (this.stringNotNull(tableComment) ? tableComment + " " : "") + "]服务实现.");
        bw.newLine();
        bw.write("@Service");
        bw.newLine();
        bw.write("@Transactional(readOnly = true)");
        bw.newLine();
        bw.write("public class " + className + "{");
        bw.newLine();
        bw.newLine();
        bw.write("    @Autowired");
        bw.newLine();
        bw.write("	  private " + this.daoName + " " + processResultMapId(this.daoName)+";");
        bw.newLine();
        bw.newLine();
        this.write(bw, "	/**                                                                                                                                      ");
        this.write(bw, "	 * 分页列表                                                                                                                              ");
        this.write(bw, "	 */                                                                                                                                      ");
        bw.write("    public IPage<"+this.beanName+"> findListByPage(Page<"+this.beanName+"> page, "+this.beanName+" "+processResultMapId(this.beanName)+"){");
        bw.newLine();
        bw.write("        return "+processResultMapId(this.daoName)+".findList(page,"+processResultMapId(this.beanName)+");");
        bw.newLine();
        bw.write("    }");
        bw.newLine();
        bw.newLine();
        this.write(bw, "	/**                                                                                                                                      ");
        this.write(bw, "	 * 列表                                                                                                                              ");
        this.write(bw, "	 */                                                                                                                                      ");
        bw.write("    public List<"+this.beanName+"> findList("+this.beanName+" "+processResultMapId(this.beanName)+"){");
        bw.newLine();
        bw.write("        return "+processResultMapId(this.daoName)+".findList("+processResultMapId(this.beanName)+");");
        bw.newLine();
        bw.write("    }");
        bw.newLine();
        bw.newLine();
        this.write(bw, "	/**                                                                                                                                      ");
        this.write(bw, "	 * 详情                                                                                                                              ");
        this.write(bw, "	 */                                                                                                                                      ");
        bw.write("    public "+this.beanName+" getById(int id){");
        bw.newLine();
        bw.write("        return "+processResultMapId(this.daoName)+".selectById(id);");
        bw.newLine();
        bw.write("    }");
        bw.newLine();
        bw.newLine();
        this.write(bw, "	/**                                                                                                                                      ");
        this.write(bw, "	 * 保存                                                                                                                              ");
        this.write(bw, "	 */                                                                                                                                      ");
        bw.write("    @Transactional(readOnly = false)");
        bw.newLine();
        bw.write("    public void insert(" +this.beanName+" "+processResultMapId(this.beanName)+"){");
        bw.newLine();
        bw.write("        "+processResultMapId(this.daoName)+".insert("+processResultMapId(this.beanName)+");");
        bw.newLine();
        bw.write("    }");
        bw.newLine();
        bw.newLine();
        this.write(bw, "	/**                                                                                                                                      ");
        this.write(bw, "	 * 修改                                                                                                                              ");
        this.write(bw, "	 */                                                                                                                                      ");
        bw.write("    @Transactional(readOnly = false)");
        bw.newLine();
        bw.write("    public void update(" +this.beanName+" "+processResultMapId(this.beanName)+"){");
        bw.newLine();
        bw.write("    UpdateWrapper<"+this.beanName+"> updateWrapper = new UpdateWrapper<>();");
        bw.newLine();
        bw.write("    updateWrapper.eq(\"id\", "+processResultMapId(this.beanName)+".getId());");
        bw.newLine();
        bw.write("        "+processResultMapId(this.daoName)+".update("+processResultMapId(this.beanName)+",updateWrapper);");
        bw.newLine();
        bw.write("    }");
        bw.newLine();
        bw.newLine();
        this.write(bw, "	/**                                                                                                                                      ");
        this.write(bw, "	 * 删除                                                                                                                              ");
        this.write(bw, "	 */                                                                                                                                        ");
        bw.write("    @Transactional(readOnly = false)");
        bw.newLine();
        bw.write("    public void delete(" +processType(types.get(0))+" id){");
        bw.newLine();
        bw.write("        "+processResultMapId(this.daoName)+".deleteById(id);");
        bw.newLine();
        bw.write("    }");

        bw.newLine();
        bw.newLine();
        bw.write("}");
        bw.flush();
        bw.close();
    }
    
    /**
     * 生成Controller
     */
    private void buildController(String path, String className, String packName, List<String> columns, List<String> types, List<String> comments, String tableComment) throws IOException {
        String modelNote = this.stringNotNull(tableComment) ? tableComment.replace("表", "") : "";
        File folder = new File(path);
        if (!folder.exists()) {
            folder.mkdir();
        }

        File beanFile = new File(path, className + ".java");
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(beanFile)));
        
        this.write(bw, "package " + packName + ";                                                                                                      ");
        this.write(bw, "                                                                                                                                             ");
        this.write(bw, "import "+this.bean_package+"."+this.beanName+";                                                                                                  ");
        this.write(bw, "import " + this.service_package + "." + this.serviceName + ";                                                                                          ");
        this.write(bw, "import com.baomidou.mybatisplus.core.metadata.IPage;                                                                                                        ");
        this.write(bw, "import com.baomidou.mybatisplus.extension.plugins.pagination.Page;                                                                                                        ");
        this.write(bw, "import com.loit.loitcommon.json.AjaxJson;                                                                                                        ");
        this.write(bw, "import com.loit.loitcommon.utils.ExportExcel;                                                                                                        ");
        this.write(bw, "import io.swagger.annotations.*;                                                                                                             ");
        this.write(bw, "import org.slf4j.Logger;                                                                                                                     ");
        this.write(bw, "import org.slf4j.LoggerFactory;                                                                                                              ");
        this.write(bw, "import org.springframework.beans.factory.annotation.Autowired;                                                                               ");
        this.write(bw, "import org.springframework.web.bind.annotation.*;                                                                                            ");
        this.write(bw, "import springfox.documentation.annotations.ApiIgnore;                                                                                        ");
        this.write(bw, "import javax.servlet.http.HttpServletResponse;                                                                                                                       ");
        this.write(bw, "import java.util.List;                                                                                                                       ");
        this.write(bw, "                                                                                                                                             ");
        this.write(bw, "                                                                                                                                             ");
        buildClassComment(bw,  "[" + modelNote + "]接口");
        this.write(bw, "");
        this.write(bw, "@RestController                                                                                                                              ");
        this.write(bw, "@RequestMapping(value = \""+request+processResultMapId(this.beanName)+"\")                                                                                                         ");
        this.write(bw, "@Api(tags = \"" +  "[" + modelNote + "]接口" + "\",  value = \""+this.beanName+"Controller\")                                                                                              ");
        this.write(bw, "public class "+this.beanName+"Controller {                                                                                                            ");
        this.write(bw, "                                                                                                                                             ");
        this.write(bw, "	/**                                                                                                                                      ");
        this.write(bw, "	 * 日志工具                                                                                                                              ");
        this.write(bw, "	 */                                                                                                                                      ");
        this.write(bw, "	private Logger logger = LoggerFactory.getLogger(this.getClass());                                                                        ");
        this.write(bw, "	                                                                                                                                         ");
        this.write(bw, "	@Autowired                                                                                                                               ");
        this.write(bw, "	private " + this.serviceName + " " + processResultMapId(this.serviceName) + ";                                                                                                 ");
        this.write(bw, "	                                                                                                                                         ");
        this.write(bw, "                                                                                                                                             ");
        this.write(bw, "	/**                                                                                                                                      ");
        this.write(bw, "	 * 分页列表                                                                                                                          ");
        this.write(bw, "	 */                                                                                                                                      ");
        this.write(bw, "	@ApiOperation(value = \"分页列表\", notes = \"分页列表\")                                                                        ");
        this.write(bw, "	@ApiImplicitParams({                                                                                                                     ");
        this.write(bw, "	        @ApiImplicitParam(paramType = \"query\", name = \"current\", value = \"当前页码\", required = true, dataType = \"Long\"),  ");
        this.write(bw, "	        @ApiImplicitParam(paramType = \"query\", name = \"size\", value = \"分页大小\", required = true, dataType = \"Long\"),");
        
        for (int i = 1; i < columns.size(); i++) {
            String tempField = processField(columns.get(i));
            String type = processType(types.get(i));
            String comment = comments.get(i);
            String code = "	        @ApiImplicitParam(paramType = \"query\", name = \""+tempField+"\", value = \""+comment+"\", required = false, dataType = \""+type+"\")";
            if(i < columns.size() - 1){
            	code += ",";
            }
            this.write(bw, code);
        }
        this.write(bw, "	})");
        this.write(bw, "	@RequestMapping(value = \"/page\", method = RequestMethod.GET)                                                                           ");
        this.write(bw, "	public AjaxJson findPage(@ApiIgnore "+this.beanName+" "+this.processResultMapId(this.beanName)+", Long current, Long size) {                                  ");
        this.write(bw, "		AjaxJson json = new AjaxJson();                                                                                                      ");
        this.write(bw, "		IPage<"+this.beanName+"> page = " + processResultMapId(this.serviceName) + ".findListByPage(new Page<"+this.beanName+">(current, size), "+this.processResultMapId(this.beanName)+");                                     ");
        this.write(bw, "		json.put(\"page\", page);                                                                                                            ");
        this.write(bw, "		return json;                                                                                                                         ");
        this.write(bw, "	}                                                                                                                                        ");
        this.write(bw, "                                                                                                                                             ");
        this.write(bw, "	/**                                                                                                                                      ");
        this.write(bw, "	 * 详情                                                                                                                              ");
        this.write(bw, "	 */                                                                                                                                    ");
        this.write(bw, "	@ApiOperation(value = \"详情\", notes = \"根据id获取详情信息\")                                                                  ");
        this.write(bw, "	@ApiImplicitParam(paramType = \"path\", name = \"id\", value = \""+modelNote+"id\", required = true, dataType = \"Long\")                         ");
        this.write(bw, "	@RequestMapping(value = \"/{id}\", method = RequestMethod.GET)                                                                           ");
        this.write(bw, "	public AjaxJson get(@PathVariable(\"id\") Integer id) {                                                                              ");
        this.write(bw, "		"+this.beanName+" "+this.processResultMapId(this.beanName)+" = " + processResultMapId(this.serviceName) + ".getById(id);                                                                                         ");
        this.write(bw, "		AjaxJson json = new AjaxJson();                                                                                                      ");
        this.write(bw, "		json.put(\"obj\", "+this.processResultMapId(this.beanName)+");                                                                                                         ");
        this.write(bw, "		return json;                                                                                                                         ");
        this.write(bw, "	}                                                                                                                                        ");
        this.write(bw, "                                                                                                                                             ");
        this.write(bw, "	/**                                                                                                                                      ");
        this.write(bw, "	 * 保存                                                                                                                              ");
        this.write(bw, "	 */                                                                                                                                      ");
        this.write(bw, "	@ApiOperation(value = \"保存\", notes = \"保存\")                                                                                ");
        this.write(bw, "	@RequestMapping(value = \"/save\", method = RequestMethod.POST)                                                                          ");
        this.write(bw, "	public AjaxJson save(@RequestBody "+this.beanName+" "+this.processResultMapId(this.beanName)+") {                                                                                   ");
        this.write(bw, "		AjaxJson json = new AjaxJson();                                                                                                      ");
        this.write(bw, "		try {                                                                                                                                ");
        this.write(bw, "			" + processResultMapId(this.serviceName) + ".insert("+this.processResultMapId(this.beanName)+");                                                                                                ");
        this.write(bw, "			json.setMsg(\"保存成功\");                                                                                                       ");
        this.write(bw, "		} catch (Exception e) {                                                                                                              ");
        this.write(bw, "			e.printStackTrace();                                                                                                             ");
        this.write(bw, "			return AjaxJson.returnExceptionInfo(\"保存异常\");                                                                               ");
        this.write(bw, "		}                                                                                                                                    ");
        this.write(bw, "		return json;                                                                                                                         ");
        this.write(bw, "	}                                                                                                                                        ");
        this.write(bw, "	                                                                                                                                         ");
        this.write(bw, "	/**                                                                                                                                      ");
        this.write(bw, "	 * 修改                                                                                                                              ");
        this.write(bw, "	 */                                                                                                                                      ");
        this.write(bw, "	@ApiOperation(value = \"修改\", notes = \"修改\")                                                                                ");
        this.write(bw, "	@RequestMapping(value = \"/update\", method = RequestMethod.POST)                                                                        ");
        this.write(bw, "	public AjaxJson update(@RequestBody "+this.beanName+" "+this.processResultMapId(this.beanName)+") {                                                                                 ");
        this.write(bw, "		AjaxJson json = new AjaxJson();                                                                                                      ");
        this.write(bw, "		try {                                                                                                                                ");
        this.write(bw, "			" + processResultMapId(this.serviceName) + ".update("+this.processResultMapId(this.beanName)+");                                                                                                ");
        this.write(bw, "			json.setMsg(\"修改成功\");                                                                                                       ");
        this.write(bw, "		} catch (Exception e) {                                                                                                              ");
        this.write(bw, "			e.printStackTrace();                                                                                                             ");
        this.write(bw, "			return AjaxJson.returnExceptionInfo(\"修改异常\");                                                                               ");
        this.write(bw, "		}                                                                                                                                    ");
        this.write(bw, "		return json;                                                                                                                         ");
        this.write(bw, "	}                                                                                                                                        ");
        this.write(bw, "	                                                                                                                                         ");
        this.write(bw, "	/**                                                                                                                                      ");
        this.write(bw, "	 * 删除                                                                                                                              ");
        this.write(bw, "	 */                                                                                                                                      ");
        this.write(bw, "	@ApiOperation(value = \"删除\", notes = \"删除\")                                                                                ");
        this.write(bw, "	@ApiImplicitParam(paramType = \"path\", name = \"id\", value = \""+modelNote+"id\", required = true, dataType = \""+processType(types.get(0))+"\")                         ");
        this.write(bw, "	@RequestMapping(value = \"/{id}\", method = RequestMethod.DELETE)                                                                        ");
        this.write(bw, "	public AjaxJson delete(@PathVariable(\"id\") "+processType(types.get(0))+" id) {                                                                               ");
        this.write(bw, "		AjaxJson json = new AjaxJson();                                                                                                      ");
        this.write(bw, "		try {                                                                                                                                ");
        this.write(bw, "			" + processResultMapId(this.serviceName) + ".delete(id);                                                                                  ");
        this.write(bw, "			json.setMsg(\"删除成功!\");                                                                                                      ");
        this.write(bw, "		} catch (Exception e) {                                                                                                              ");
        this.write(bw, "			e.printStackTrace();                                                                                                             ");
        this.write(bw, "			return AjaxJson.returnExceptionInfo(\"删除失败\" + e.getMessage());                                                              ");
        this.write(bw, "		}                                                                                                                                    ");
        this.write(bw, "		return json;                                                                                                                         ");
        this.write(bw, "	}                                                                                                                                        ");
        this.write(bw, "	                                                                                                                                         ");
        this.write(bw, "    /**                                                                                                                                         ");
        this.write(bw, "     * 导出                                                                                                                                         ");
        this.write(bw, "     */                                                                                                                                         ");
        this.write(bw, "    @ApiOperation(value = \"导出\", notes = \"导出\")                                                                                                                                         ");
        this.write(bw, "    @ApiImplicitParams({                                                                                                                                         ");
        for (int i = 1; i < columns.size(); i++) {
            String tempField = processField(columns.get(i));
            String type = processType(types.get(i));
            String comment = comments.get(i);
            String code = "	        @ApiImplicitParam(paramType = \"query\", name = \""+tempField+"\", value = \""+comment+"\", required = false, dataType = \""+type+"\")";
            if(i < columns.size() - 1){
                code += ",";
            }
            this.write(bw, code);
        }
        this.write(bw, "	})");
        this.write(bw, "    @GetMapping(value = \"/export\")                                                                                                                                         ");
        this.write(bw, "    public void export(@ApiIgnore "+this.beanName+" "+this.processResultMapId(this.beanName)+", HttpServletResponse response) {                                                                                                                                         ");
        this.write(bw, "        List<"+this.beanName+"> list = " + processResultMapId(this.serviceName) + ".findList("+this.processResultMapId(this.beanName)+");                                                                                                                                     ");
        this.write(bw, "        try {                                                                                                                                     ");
        this.write(bw, "            new ExportExcel(null, "+this.beanName+".class).setDataList(list).write(response, \""+modelNote+"数据.xlsx\").dispose();                                                                                                                                 ");
        this.write(bw, "        } catch (Exception e) {                                                                                                                                     ");
        this.write(bw, "            e.printStackTrace();                                                                                                                                 ");
        this.write(bw, "        }                                                                                                                                     ");
        this.write(bw, "    }                                                                                                                                        ");
        this.write(bw, "	                                                                                                                                         ");
        this.write(bw, "}                                                                                                                                            ");
        
        bw.flush();
        bw.close();
    }

    /**
     * 字符串空判断, null返回false
     *
     * @param str
     * @return
     */
    private boolean stringNotNull(String str) {
        if (null != str && !"".equals(str)) {
            return true;
        }
        return false;
    }
    
    /**
     * 输出
     */
    private void write(BufferedWriter bw, String txt) throws IOException{
    	bw.write(txt);                                                                                               
        bw.newLine();
    }

    /**
     * 获取当前时间
     *
     * @return
     */
    private String getDate() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        return format.format(new Date());
    }
}
